package com.zyl.file.platform;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.amazonaws.AmazonServiceException;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.model.AmazonS3Exception;
import com.amazonaws.services.s3.model.ListPartsRequest;
import com.amazonaws.services.s3.model.PartListing;
import com.amazonaws.services.s3.model.PartSummary;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.SftpATTRS;
import com.jcraft.jsch.SftpException;
import com.zyl.file.constant.StateConstants;
import com.zyl.file.dto.SplitUploadDTO;
import com.zyl.file.dto.SplitUploadRecordDTO;
import com.zyl.file.exception.MyException;
import com.zyl.file.mapper.StEquipmentMapper;
import com.zyl.file.mapper.StFileMapper;
import com.zyl.file.po.StEquipment;
import com.zyl.file.po.StFile;
import com.zyl.file.result.ResultCode;
import com.zyl.file.util.AssertUtils;
import com.zyl.file.util.FtpUtils;
import com.zyl.file.vo.SplitUploadVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;

import javax.annotation.Resource;
import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * @author zyl
 * @Description
 * @since 2024/1/18 17:19
 */
@Slf4j
public class SftpFileStorage extends FileStorage{

    @Resource
    private StEquipmentMapper stEquipmentMapper;

    @Resource
    private Map<String, AmazonS3> amazonS3ClientMap;

    @Resource
    private StFileMapper stFileMapper;

    /**
     * 分片文件临时存储文件夹
     */
    private String temporaryFolder = "/temporaryFolder";

    /**
     * 加密密钥
     */
    @Value("${upload.encrypt.encrypt-key:8a08826984224746}")
    private String ENCRYPT_KEY;

    /**
     * 加密标识符（用于区分加密、未加密数据）
     */
    @Value("${upload.encrypt.encrypt-index:<ENCRYPTED>}")
    private String ENCRYPT_INDEX;

    @Override
    public SplitUploadDTO initTask(SplitUploadVO param, Long userId) {
        StFile byIdentifier = getByIdentifier(param.getIdentifier());
        if (!ObjectUtil.isNull(byIdentifier)) {
            throw new MyException(ResultCode.PARAM_ERROR, "本次上传有内容一样的文件，只能成功上传其中一个");
        }
        StFile task = new StFile();
        String fileName = param.getFileName();
        String fileName1 = IdUtil.randomUUID();
        String suffix = fileName.substring(fileName.lastIndexOf(".") + 1, fileName.length());
        String key = "";
        String bucketName = "";
        String uploadId = "";
        Date currentDate = new Date();
        //通过指定设备id，来确定存储路径/存储方式
        StEquipment stEquipment = stEquipmentMapper.selectById(param.getEquipmentId());
        bucketName = stEquipment.getBasePath();
        key = StrUtil.format("{}/{}.{}", DateUtil.format(currentDate, "YYYY-MM-dd"), fileName1, suffix);
        uploadId = IdUtil.randomUUID();
        task.setUrl(StrUtil.format("{}{}/{}", stEquipment.getStorageAddress(), bucketName, key));
        int chunkNum = (int) Math.ceil(param.getTotalSize() * 1.0 / param.getChunkSize());
        task.setBucketName(bucketName)
                .setChunkNum(chunkNum)
                .setChunkSize(param.getChunkSize())
                .setSize(param.getTotalSize())
                .setFileMd5(param.getIdentifier())
                .setOriginalFilename(fileName)
                .setFilename(fileName1)
                .setExt(suffix)
                .setFilePath(bucketName + "/" + key)
                .setObjectKey(key)
                .setCreateUser(userId)
                .setUploadId(uploadId)
                .setBusiBatchNo(param.getBusiBatchNo())
                .setSourceFileMd5(param.getSourceFileMd5())
                .setEquipmentId(param.getEquipmentId());
        stFileMapper.insert(task);
        SplitUploadRecordDTO dto = new SplitUploadRecordDTO();
        BeanUtil.copyProperties(task, dto);
        return new SplitUploadDTO()
                .setFinished(false)
                .setTaskRecord(dto)
                .setPath(getPath(stEquipment.getStorageAddress(), bucketName, key));
    }

    @Override
    public SplitUploadDTO getTaskInfo(String identifier, Integer isEncrypt) {
        long l = System.currentTimeMillis();

        StFile task = getByIdentifier(identifier);
        long l1 = System.currentTimeMillis();
        System.out.println("1:" + (l1 - l));
        if (task == null) {
            return null;
        }
        SplitUploadRecordDTO dto = new SplitUploadRecordDTO();
        BeanUtil.copyProperties(task, dto);
        //通过指定设备id，来确定存储路径/存储方式
        StEquipment stEquipment = stEquipmentMapper.selectOne(new LambdaQueryWrapper<StEquipment>().eq(StEquipment::getId, task.getEquipmentId()));
        //测试存储设备连接
//        storageEquipmentService.testConnect(stEquipment);


        SplitUploadDTO result = new SplitUploadDTO().setFinished(true).setTaskRecord(dto).setPath(getPath(stEquipment.getStorageAddress(), task.getBucketName(), task.getObjectKey()));
        long l2 = System.currentTimeMillis();
        System.out.println("2：" + (l2 - l1));
        if (StateConstants.COMMON_ONE.equals(task.getIsUploadOk())){
            return result;
        }
        //当任意一个存储设备上成功上传过某个文件，再向另一个存储设备上传相同的文件，不在这个设备重新上传，直接秒传
        //如果是nas存储
        //判断文件是否上传成功
        SftpATTRS lstat = null;
        ChannelSftp channelSftp = null;
        try {
            channelSftp = FtpUtils.getConnect(stEquipment.getDomainName().split(":")[0], Integer.valueOf(stEquipment.getDomainName().split(":")[1]), stEquipment.getAccessKey(), stEquipment.getAccessSecret());
            lstat = channelSftp.lstat(task.getFilePath());

            if (lstat == null) {
                //            if (!StateConstants.COMMON_ONE.equals(task.getIsUploadOk())){
                //此步骤只徐然返回的list的size对应已上传到数量就行，用于前端来判断续传前已经传了多少个子文件了
                List<PartSummary> exitPartList = new ArrayList<>();
                //1、根据index来合并指定temporaryFolder里面的分片文件
                File file = new File(stEquipment.getBasePath() + temporaryFolder + File.separator
                        + result.getTaskRecord().getBusiBatchNo() + File.separator
                        + result.getTaskRecord().getFileMd5());
                //获取分片文件集
                if (null != file.listFiles() && file.listFiles().length > 0) {
                    for (File item : file.listFiles()) {
                        PartSummary partSummary = new PartSummary();
                        partSummary.setPartNumber(Integer.valueOf(item.getName().split("-")[0]));
                        partSummary.setSize(item.length());
                        exitPartList.add(partSummary);
                    }
                }
                result.setFinished(false).getTaskRecord().setExitPartList(exitPartList);
            } else {
//                    cacheDelService.isEmptyFileByTempDir(task.getFilePath(), task.getId(), task.getExt(), stEquipment.getDomainName().split(":")[0],
//                            Integer.valueOf(stEquipment.getDomainName().split(":")[1]), stEquipment.getAccessKey(), stEquipment.getAccessSecret());
            }
        } catch (SftpException e) {
            log.error("没有文件,{}",e);
            result.setFinished(false);
        } catch (Exception e) {
            log.error("ftp连接失败,{}",e);
        } finally {
            channelSftp.disconnect();
        }
        long l3 = System.currentTimeMillis();
        System.out.println("2：" + (l3 - l2));
        return result;
    }

    @Override
    public String genPreSignUploadUrl(String identifier, Integer partNumber, String type, Boolean isOpen) {
        return null;
    }

    @Override
    public StFile merge(String identifier, Boolean isFlat) {
        return null;
    }

    @Override
    public void close() throws Exception {

    }
}
